home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / c / tde31.zip / CONSOLE.C < prev    next >
C/C++ Source or Header  |  1993-08-29  |  53KB  |  1,554 lines

  1. /*
  2.  * All video and keyboard functions were gathered into one file.
  3.  *
  4.  * This file contains the keyboard and video i/o stuff.  Most of this stuff
  5.  * is specific to the PC hardware, but it should be easily modified when
  6.  * porting to other platforms.  With a few key functions written in
  7.  * assembly, we have fairly fast video performance and good keyboard control.
  8.  * Incidentally, the commented C code in the functions perform the same
  9.  * function as the assembly code.  In earlier versions of TDE, I didn't
  10.  * update the commented C code when I changed the assembly code.  The
  11.  * C and assembly should be equivalent in version 2.2.
  12.  *
  13.  * Although using a curses type package would be more portable, curses
  14.  * can be slow on PCs.  Let's keep our video and keyboard routines in
  15.  * assembly.  I feel the need for speed.
  16.  *
  17.  * Being that TDE 2.2 keeps an accurate count of characters in each line, we
  18.  * can allow the user to enter any ASCII or Extended ASCII key.
  19.  *
  20.  * Determining the video adapter type on the PC requires a function.  In
  21.  *  TDE, that function is:
  22.  *
  23.  *                void video_config( struct vcfg *cfg )
  24.  *
  25.  * video_config( ) is based on Appendix C in _Programmer's Guide to
  26.  *  PC & PS/2 Video Systems_ by Richard Wilton.
  27.  *
  28.  * See:
  29.  *
  30.  *   Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_,
  31.  *    Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521.
  32.  *    ISBN 1-55615-103-9.
  33.  *
  34.  *
  35.  * New editor name:  TDE, the Thomson-Davis Editor.
  36.  * Author:           Frank Davis
  37.  * Date:             June 5, 1991, version 1.0
  38.  * Date:             July 29, 1991, version 1.1
  39.  * Date:             October 5, 1991, version 1.2
  40.  * Date:             January 20, 1992, version 1.3
  41.  * Date:             February 17, 1992, version 1.4
  42.  * Date:             April 1, 1992, version 1.5
  43.  * Date:             June 5, 1992, version 2.0
  44.  * Date:             October 31, 1992, version 2.1
  45.  * Date:             April 1, 1993, version 2.2
  46.  * Date:             June 5, 1993, version 3.0
  47.  * Date:             August 29, version 3.1
  48.  *
  49.  * This code is released into the public domain, Frank Davis.
  50.  * You may distribute it freely.
  51.  */
  52.  
  53.  
  54. #include "tdestr.h"
  55. #include "common.h"
  56. #include "define.h"
  57. #include "tdefunc.h"
  58.  
  59. #include <bios.h>               /* for direct BIOS keyboard input */
  60.  
  61.  
  62. /*******************************************************/
  63. /*                                                     */
  64. /*  1) initialize the video and keyboard structures    */
  65. /*                                                     */
  66. /*******************************************************/
  67.  
  68.  
  69. /*
  70.  *   BIOS Data Areas
  71.  *
  72.  *   See:
  73.  *
  74.  *      IBM Corp., _Technical Reference:  Personal Computer AT_,
  75.  *      Boca Raton, Florida, 1984, IBM part no. 1502494,
  76.  *      pp 5-29 thru 5-32.
  77.  *
  78.  *  These addresses, variable names, types, and descriptions are directly
  79.  *   from the IBM AT Technical Reference manual, BIOS listing, copyright IBM.
  80.  *
  81.  *   Address  Name           Type   Description
  82.  *   0x0449   CRT_MODE       Byte   Current CRT mode
  83.  *   0x044a   CRT_COLS       Word   Number columns on screen
  84.  *   0x044c   CRT_LEN        Word   length of regen buffer, video buffer, bytes
  85.  *   0x044e   CRT_START      Word   Starting address of regen buffer
  86.  *   0x0450   CURSOR_POSN    Word   cursor for each of up to 8 pages.
  87.  *   0x0460   CURSOR_MODE    Word   current cursor mode setting.
  88.  *   0x0462   ACTIVE_PAGE    Byte   Current page
  89.  *   0x0463   ADDR_6845      Word   base address for active display card
  90.  *   0x0465   CRT_MODE_SET   Byte   current mode of display card
  91.  *   0x0466   CRT_PALETTE    Byte   overscan color for CGA, EGA, and VGA.
  92.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  93.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  94.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  95.  *   0x046c   timer_low      Word   Low word of timer count
  96.  *   0x046e   timer_high     Word   High word of timer count
  97.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  98.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  99.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  100.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  101.  *   0x0485   POINTS         Word   Height of character matrix
  102.  *   0x0487   INFO           Byte   EGA and VGA display data
  103.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  104.  *   0x0489   flags          Byte   Miscellaneous flags
  105.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  106.  *   0x048A   DCC            Byte   Display Combination Code
  107.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  108.  */
  109. void video_config( struct vcfg *cfg )
  110. {
  111. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  112.  
  113. struct LOWMEMVID
  114. {
  115.    char     vidmode;           /* 0x449 */
  116.    unsigned scrwid;            /* 0x44A */
  117.    unsigned scrlen;            /* 0x44C */
  118.    unsigned scroff;            /* 0x44E */
  119.    struct   LOCATE
  120.    {
  121.       unsigned char col;
  122.       unsigned char row;
  123.    } csrpos[8];                /* 0x450 */
  124.    struct   CURSIZE
  125.    {
  126.       unsigned char end;
  127.       unsigned char start;
  128.    } csrsize;                  /* 0x460 */
  129.    char      page;             /* 0x462 */
  130.    unsigned  addr_6845;        /* 0x463 */
  131.    char      crt_mode_set;     /* 0x465 */
  132.    char      crt_palette;      /* 0x466 */
  133.    char      system_stuff[29]; /* 0x467 */
  134.    char      rows;             /* 0x484 */
  135.    unsigned  points;           /* 0x485 */
  136.    char      ega_info;         /* 0x487 */
  137.    char      info_3;           /* 0x488 */
  138.    char      skip[13];         /* 0x489 */
  139.    char      kb_flag_3;        /* 0x496 */
  140. } vid;
  141. struct LOWMEMVID _far *pvid = &vid;
  142. #pragma pack( )    /* revert to previously defined pack pragma. */
  143.  
  144. union REGS in, out;
  145. unsigned char temp, active_display;
  146.  
  147.    /*
  148.     * Move system information into our video structure.
  149.     */
  150.    _fmemmove( pvid, (void far *)0x00000449l, sizeof( vid ) );
  151.  
  152.    cfg->rescan = FALSE;
  153.    in.x.ax =  0x1a00;
  154.    int86( VIDEO_INT, &in, &out );
  155.    temp = out.h.al;
  156.    active_display = out.h.bl;
  157.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  158.       g_display.adapter = VGA;
  159.    else {
  160.       in.h.ah =  0x12;
  161.       in.h.bl =  0x10;
  162.       int86( VIDEO_INT, &in, &out );
  163.       if (out.h.bl != 0x10) {         /* EGA */
  164.          if (vid.ega_info & 0x08)
  165.             g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA;
  166.          else
  167.             g_display.adapter = EGA;
  168.       } else if (vid.addr_6845 == 0x3d4)
  169.          g_display.adapter = CGA;
  170.       else
  171.          g_display.adapter = MDA;
  172.    }
  173.  
  174.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  175.       if (g_display.adapter == CGA)
  176.          cfg->rescan = TRUE;
  177.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407;
  178.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607;
  179.    } else {
  180.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b;
  181.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c;
  182.    }
  183.  
  184.    cfg->mode = vid.vidmode;
  185.    if (vid.addr_6845 == 0x3D4) {
  186.       cfg->color = TRUE;
  187.       cfg->videomem = (void far *)0xb8000000l;
  188.    } else {
  189.       cfg->color = FALSE;
  190.       cfg->videomem = (void far *)0xb0000000l;
  191.    }
  192.  
  193.    /*
  194.     * let save the overscan color
  195.     */
  196.    g_display.old_overscan = vid.crt_palette;
  197.  
  198.  
  199.    /*
  200.     * Get keyboard type.  Since there is no interrupt that determines
  201.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  202.     * This method is not always foolproof on clones.
  203.     */
  204.    if ((vid.kb_flag_3 & 0x10) != 0)
  205.       mode.enh_kbd = TRUE;
  206.    else
  207.       mode.enh_kbd = FALSE;
  208.    if (mode.enh_kbd == FALSE)
  209.       simulate_enh_kbd( 1 );
  210. }
  211.  
  212.  
  213. /*********************************************/
  214. /*                                           */
  215. /*  2) keyboard i/o routines, PC specific    */
  216. /*                                           */
  217. /*********************************************/
  218.  
  219.  
  220. /*
  221.  * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and
  222.  * modified extensively by Frank Davis.
  223.  *
  224.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  225.  * problem when getch() is used in a program.  For example, instead of returning
  226.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  227.  * of using getch(), I use the following function ..."
  228.  *
  229.  * Tom, thanks for the info and solution.  I'm sure your function will be
  230.  * be appreciated by everyone with ANSI key defs, Frank.
  231.  */
  232.  
  233. /*
  234.  * Name:    getkey
  235.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  236.  *          redefined keys)
  237.  * Date:    July 2, 1991
  238.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  239.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  240.  * Passed:  None
  241.  * Notes:   Uses the BIOS to read the next keyboard character.  Service 0x00
  242.  *           is the XT keyboard read.  Service 0x10 is the extended keyboard
  243.  *           read.  Test for a bunch of special cases.  Allow the user to enter
  244.  *           any ASCII or Extended ASCII code as a normal text characters.
  245.  *
  246.  *          Control @ is defined as 0.  we need to do a special test
  247.  *           for this key, otherwise it's interpretted as an Alt key.  It's
  248.  *           the only "regular" Control key that returns 0 in AL and the scan
  249.  *           byte in AH.  The "regular" Control keys are those in the range
  250.  *           0-31 and they return the Control character in AL and the scan
  251.  *           code in AH.  All of the Alt + keys return 0 in AL and
  252.  *           the scan code in ah.
  253.  *
  254.  *          This function was written for US keyboards.  It may have to be
  255.  *           modified for other keyboards, eg. Belgium, Canada, Czech,
  256.  *           Slovak, Denmark, France, Germany, etc...
  257.  *
  258.  *          if Ctrl-Break is pressed, it returns 0xffff as the key pressed.
  259.  *           let's set it to CONTROL_BREAK == 269 and do nothing.
  260.  */
  261. int getkey( void )
  262. {
  263. unsigned key, num_lock, control, shift;
  264. register scan;
  265. register unsigned lo;
  266.  
  267. /*
  268.  * this code is used during testing to check the amount of memory
  269.  *    in the near heap.
  270.  *
  271.  * char buff[MAX_COLS];
  272.  * ultoa( _memavl( ), buff, 10 );
  273.  * s_output( "h=       ", g_display.mode_line, 37, g_display.mode_color );
  274.  * s_output( buff, g_display.mode_line, 39, g_display.mode_color );
  275.  */
  276.  
  277.    /*
  278.     * lets spin on waitkey until the user presses a key.  waitkey polls
  279.     *  the keyboard and returns 0 when a key is waiting.
  280.     */
  281.    while (waitkey( mode.enh_kbd ));
  282.  
  283.    /*
  284.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  285.     *   and the ascii key code in al, lo part of key.  If the character was
  286.     *   entered via ALT-xxx, the scan code, hi part of key, is 0.
  287.     */
  288.    if (mode.enh_kbd) {
  289.       key = _bios_keybrd( 0x10 );
  290.       lo  = _bios_keybrd( 0x12 );
  291.  
  292.       /*
  293.        * couple of special cases:
  294.        *   on the numeric keypad, some keys return 0xe0 in the lo byte.
  295.        *   1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0.
  296.        *   we need to let this get thru as an Extended ASCII char.  2) although
  297.        *   we could make the cursor pad keys do different functions than the
  298.        *   numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero
  299.        *   and forget about support for those keys.
  300.        */
  301.       if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0)
  302.          key = key & 0xff00;
  303.    } else {
  304.       key = _bios_keybrd( 0 );
  305.       lo  = _bios_keybrd( 2 );
  306.    }
  307.    num_lock = lo & 0x20;
  308.    control  = lo & 0x04;
  309.    shift    = lo & 0x03;
  310.    scan = (key & 0xff00) >> 8;
  311.    lo = key & 0X00FF;
  312.  
  313.    if (lo == 0) {
  314.       /*
  315.        * special case for Control @, which is defined as 0 or NULL.
  316.        */
  317.       if (scan == 3)
  318.          lo = 430;
  319.  
  320.       /*
  321.        * when first byte is 0, map it above 256, so that we can
  322.        *  let ALT-xxx keys map to their 'natural' place.  In
  323.        *  otherwords, use 0-255 as normal text characters and
  324.        *  those >= 256 are function keys.
  325.        */
  326.       else
  327.          lo = scan | 0x100;
  328.  
  329.    /*
  330.     * now test for Control-Break.  let's set this to do nothing in the
  331.     *  editor.  manually map Control-Break to 269 - DO NOT assign
  332.     *  any function to 269.
  333.     */
  334.    } else if (key == 0xffff)
  335.       lo = CONTROL_BREAK;
  336.  
  337.  
  338.    /*
  339.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  340.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  341.     * 0x7f character, then they can enter it via ALT+xxx.
  342.     */
  343.    if (scan == 14 && lo == 0x7f)
  344.       lo = 8;
  345.  
  346.    /*
  347.     * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad
  348.     *  ENTER and / keys are read through the BIOS interrupt 16h, only E0h
  349.     *  is seen since the interrupt only gives one-byte scan codes."
  350.     */
  351.    else if (scan == 0xe0) {
  352.       /*
  353.        * plain Grey Enter
  354.        */
  355.       if (lo == 13 && !shift)
  356.          lo = 285;
  357.       /*
  358.        * shift Grey Enter
  359.        */
  360.       else if (lo == 13)
  361.          lo = 298;
  362.       /*
  363.        * control Grey Enter
  364.        */
  365.       else if (lo == 10)
  366.          lo = 299;
  367.    }
  368.  
  369.    /*
  370.     *  let's massage all of the control key combinations.
  371.     */
  372.    if (lo < 32) {
  373.  
  374.       /*
  375.        * My machine at home is sorta weird.  On every machine that I've
  376.        *  tested at the awffice, the ALT-xxx combination returns 0 for the
  377.        *  scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  378.        *  as the scan code?!?!?  I added the next two lines for my machine at
  379.        *  home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  380.        *  when they wrote my bios?
  381.        */
  382.       if (scan > 0x80)
  383.          scan = 0;
  384.  
  385.       /*
  386.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  387.        *  key is 1.  Map this to a different index into the key function
  388.        *  array just in case someone wants to define ESC or ^[ to different
  389.        *  functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  390.        */
  391.       else if (scan == 1) {
  392.          if (shift)
  393.             lo = 259;
  394.          else if (control)
  395.             lo = 260;
  396.          else
  397.             lo = 258;
  398.       }
  399.  
  400.       /*
  401.        * Scan code for Enter = 28.  Separate the various Enter keys.
  402.        */
  403.       else if (scan == 28) {
  404.          if (shift)
  405.             lo = 263;
  406.          else if (control)
  407.             lo = 264;
  408.          else
  409.             lo = 262;
  410.       }
  411.  
  412.       /*
  413.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  414.        */
  415.       else if (scan == 14) {
  416.          if (shift)
  417.             lo = 266;
  418.          else if (control)
  419.             lo = 267;
  420.          else
  421.             lo = 265;
  422.       }
  423.  
  424.       /*
  425.        * Scan code for Tab = 15.  Separate the tab key.
  426.        */
  427.       else if (scan == 15) {
  428.          lo = 268;
  429.       }
  430.  
  431.       /*
  432.        * if scan code is not 0, then a Control key was pressed.  Map
  433.        *  those keys to the WordStar commands.
  434.        */
  435.       else if (scan > 0)
  436.          lo += 430;
  437.  
  438.    } else if (!num_lock) {
  439.       switch (scan) {
  440.          /*
  441.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  442.           *  to the scroll line up function.
  443.           */
  444.          case 74 :
  445.             lo = 423;
  446.             break;
  447.  
  448.          /*
  449.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  450.           *  to the scroll line down function.  if shift grey + then stationary
  451.           *  scroll down.
  452.           */
  453.          case 78 :
  454.             lo = 424;
  455.             break;
  456.       }
  457.    }
  458.  
  459.  
  460.    /*
  461.     * let's set up for the Shift+Alt and Control+Alt keys.
  462.     *  With these key combinations, we can do the International keyboard
  463.     *  stuff, see the Microsoft MS DOS 5.0 manual pages 623-637.
  464.     */
  465.    if (lo > 256 && (shift || control)) {
  466.  
  467.       /*
  468.        * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed.
  469.        *  this is not part of the International keyboard stuff, just a way
  470.        *  to assign the horizontal scroll left and right funcs to cursor keys.
  471.        */
  472.       if (shift) {
  473.          if (lo >= 371 && lo <= 374)
  474.             lo += 55;
  475.  
  476.          /*
  477.           * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+
  478.           */
  479.          else if (lo >= 376 && lo <= 387)
  480.             lo += 86;
  481.  
  482.          /*
  483.           * internation keyboard stuff
  484.           */
  485.          else if (lo >= 272 && lo <= 309)
  486.             lo += 202;
  487.       }
  488.    }
  489.  
  490.    /*
  491.     * map the enter key to line feed.
  492.     */
  493.    if (lo == 10  &&  scan != 0)
  494.       lo = 425;
  495.    return( lo );
  496. }
  497.  
  498.  
  499. /*
  500.  * Name:    waitkey
  501.  * Purpose: call the BIOS keyboard status subfunction
  502.  * Date:    October 31, 1992
  503.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  504.  * Returns: 1 if no key ready, 0 if key is waiting
  505.  * Notes:   lets get the keyboard status so we can spin on this function until
  506.  *           the user presses a key.  some OS replacements for DOS want
  507.  *           application programs to poll the keyboard instead of rudely
  508.  *           sitting on the BIOS read key function.
  509.  */
  510. int  waitkey( int enh_keyboard )
  511. {
  512.    return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 );
  513. }
  514.  
  515.  
  516. /*
  517.  * Name:    getfunc
  518.  * Purpose: get the function assigned to key c
  519.  * Date:    July 11, 1991
  520.  * Passed:  c:  key just pressed
  521.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  522.  *           The codes in the range 0-255 are ASCII and extended ASCII chars.
  523.  */
  524. int getfunc( int c )
  525. {
  526. register int i = c;
  527. int  key_found;
  528.  
  529.    if (!g_status.key_pending) {
  530.       i = c;
  531.       if (i <= 256)
  532.          i = 0;
  533.       else
  534.          i = key_func.key[i-256];
  535.    } else {
  536.  
  537.       /*
  538.        * allow the user to enter two-key combinations
  539.        */
  540.       key_found = FALSE;
  541.       for (i=0; i < MAX_TWO_KEYS; i++) {
  542.          if (g_status.first_key == two_key_list.key[i].parent_key &&
  543.                                c == two_key_list.key[i].child_key) {
  544.             i = two_key_list.key[i].func;
  545.             key_found = TRUE;
  546.             break;
  547.          }
  548.       }
  549.       if (key_found == FALSE)
  550.          i = ERROR;
  551.    }
  552.    return( i );
  553. }
  554.  
  555.  
  556. /*
  557.  * Name:    two_key
  558.  * Purpose: set the two_key flag and prompt for the next key.
  559.  * Date:    April 1, 1992
  560.  * Notes:   this function accepts two key commands.
  561.  */
  562. int  two_key( WINDOW *arg_filler )
  563. {
  564.    s_output( "Next Key..", g_display.mode_line, 67, g_display.diag_color );
  565.    g_status.key_pending = TRUE;
  566.    g_status.first_key = g_status.key_pressed;
  567.    return( OK );
  568. }
  569.  
  570.  
  571. /*
  572.  * Name:    flush_keyboard
  573.  * Purpose: flush keys from the keyboard buffer
  574.  * Date:    June 5, 1993
  575.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  576.  * Returns: 1 if no key ready, 0 if key is waiting
  577.  * Notes:   lets get the keyboard status so we can spin on this function until
  578.  *           the user presses a key.  some OS replacements for DOS want
  579.  *           application programs to poll the keyboard instead of rudely
  580.  *           sitting on the BIOS read key function.
  581.  */
  582. void flush_keyboard( void )
  583. {
  584.    if (mode.enh_kbd) {
  585.       while (!waitkey( mode.enh_kbd ))
  586.          _bios_keybrd( 0x10 );
  587.    } else {
  588.       while (!waitkey( mode.enh_kbd ))
  589.          _bios_keybrd( 0 );
  590.    }
  591. }
  592.  
  593.  
  594. /*********************************************/
  595. /*                                           */
  596. /*  3) video output routines, PC specific    */
  597. /*                                           */
  598. /*********************************************/
  599.  
  600.  
  601. /*
  602.  * Name:    xygoto
  603.  * Purpose: To move the cursor to the required column and line.
  604.  * Date:    September 28, 1991
  605.  * Passed:  col:    desired column (0 up to max)
  606.  *          line:   desired line (0 up to max)
  607.  * Notes;   use standard BIOS video interrupt 0x10 to set the set.
  608.  */
  609. void xygoto( int col, int line )
  610. {
  611. union REGS inregs, outregs;
  612.  
  613.    inregs.h.ah = 2;
  614.    inregs.h.bh = 0;
  615.    inregs.h.dh = (unsigned char)line;
  616.    inregs.h.dl = (unsigned char)col;
  617.    int86( 0x10, &inregs, &outregs );
  618. }
  619.  
  620.  
  621. /*
  622.  * Name:    update_line
  623.  * Purpose: Display the current line in window
  624.  * Date:    June 5, 1991
  625.  * Passed:  window:  pointer to current window
  626.  * Notes:   Show string starting at column zero and if needed blank rest
  627.  *           of line.  Put max_col in cx and count down.  When we run into
  628.  *           len, cx contains number of columns to blank out.  Use the
  629.  *           fast 'rep stosw' to clear the end of line.
  630.  *          The C routine was probably fast enough, but let's do some
  631.  *           assembly because it's so fun.
  632.  *          To handle line lengths longer than 255 characters,
  633.  *           block begin and end columns were changed from real
  634.  *           to virtual columns in this display routine.
  635.  */
  636. void update_line( WINDOW *window )
  637. {
  638. text_ptr text;      /* current character of orig begin considered */
  639. char far *screen_ptr;
  640. int  off;
  641. int  attr;
  642. int  line;
  643. int  col;
  644. int  bcol;
  645. int  bc;
  646. int  ec;
  647. int  normal;
  648. int  block;
  649. int  max_col;
  650. int  block_line;
  651. int  len;
  652. int  show_eol;
  653. int  c;
  654. long rline;
  655. file_infos *file;
  656.  
  657.    if (window->rline > window->file_info->length || window->ll->len == EOF
  658.              || !g_status.screen_display)
  659.       return;
  660.    file = window->file_info;
  661.    max_col = window->end_col + 1 - window->start_col;
  662.    line = window->cline;
  663.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  664.    block = g_display.block_color;
  665.    show_eol = mode.show_eol;
  666.  
  667.    /*
  668.     * set the screen pointer to physical screen memory.
  669.     *       160 = 80 chars + 80 attr  for each line
  670.     */
  671.    screen_ptr = g_display.display_address;
  672.    off = line * 160 + window->start_col * 2;
  673.  
  674.    /*
  675.     * figure which line to display.
  676.     * actually, we could be displaying any line in any file.  we display
  677.     *  the line_buffer only if window->ll == g_status.buff_node
  678.     *  and window->ll-line has been copied to g_status.line_buff.
  679.     */
  680.    text = window->ll->line;
  681.    len  = window->ll->len;
  682.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  683.       text = (text_ptr)g_status.line_buff;
  684.       len  = g_status.line_buff_len;
  685.    }
  686.    if (mode.inflate_tabs)
  687.       text = tabout( text, &len );
  688.  
  689.    /*
  690.     * lets look at the base column.  if the line to display is shorter
  691.     *  than the base column, then set text to eol and we can't see the
  692.     *  eol either.
  693.     */
  694.    bc = window->bcol;
  695.    if (bc > 0) {
  696.       if (text == NULL) {
  697.          show_eol = FALSE;
  698.          len = 0;
  699.       } else {
  700.          if ((col = len) < bc) {
  701.             bc = col;
  702.             show_eol = FALSE;
  703.          }
  704.          text += bc;
  705.          len  -= bc;
  706.       }
  707.    }
  708.  
  709.    /*
  710.     * for display purposes, set the line length to screen width if line
  711.     *  is longer than screen.  our assembly routine uses bytes and the
  712.     *  the line length can be longer than a byte.
  713.     */
  714.    if (len > max_col)
  715.       len = max_col;
  716.  
  717.    bcol = window->bcol;
  718.    rline = window->rline;
  719.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  720.       block_line = TRUE;
  721.    else
  722.       block_line = FALSE;
  723.  
  724.    /*
  725.     * do this if 1) a box block is marked, or 2) a stream block begins
  726.     *  and ends on the same line.
  727.     */
  728.    if (block_line == TRUE && (file->block_type == BOX ||
  729.          (file->block_type == STREAM &&
  730.          rline == file->block_br && rline == file->block_er))) {
  731.  
  732.       /*
  733.        * start with the bc and ec equal to physical block marker.
  734.        */
  735.       bc = file->block_bc;
  736.       ec = file->block_ec;
  737.       if (ec < bcol || bc >= bcol + max_col)
  738.          /*
  739.           * we can't see block if ending column is less than the base col or
  740.           *  the beginning column is greater than max_col.
  741.           */
  742.          ec = bc = max_col + 1;
  743.       else if (ec < bcol + max_col) {
  744.          /*
  745.           * if the ec is less than the max column, make ec relative to
  746.           *  base column then figure the bc.
  747.           */
  748.          ec = ec - bcol;
  749.          if (bc < bcol)
  750.             bc = 0;
  751.          else
  752.             bc = bc - bcol;
  753.       } else if (bc < bcol + max_col) {
  754.          /*
  755.           * if the bc is less than the max column, make bc relative to
  756.           *  base column then figure the ec.
  757.           */
  758.          bc = bc - bcol;
  759.          if (ec > bcol + max_col)
  760.             ec = max_col;
  761.          else
  762.             ec = ec - bcol;
  763.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  764.          /*
  765.           * if the block is wider than the screen, make bc start at the
  766.           *  logical begin and make ec end at the logical end of the
  767.           *  window.
  768.           */
  769.          bc = 0;
  770.          ec = max_col;
  771.       }
  772.  
  773.  
  774.    ASSEMBLE {
  775.         /*
  776.         ; Register strategy:
  777.         ;   bl == beginning column
  778.         ;   bh == ending column
  779.         ;   dl == normal text attribute
  780.         ;   dh == block attribute
  781.         ;   cl == current virtual column
  782.         ;   ch == maximum columns in window
  783.         ;   ES:DI == screen pointer (destination)
  784.         ;   DS:SI == text pointer (source)
  785.         ;   [bp+show_eol]  == access for local C variable
  786.         */
  787.  
  788.  
  789.         push    ds                      /* MUST save ds - push it on stack */
  790.         push    si                      /* save si on stack */
  791.         push    di                      /* save di on stack */
  792.  
  793. /*
  794. ;
  795. ; set up local register variables
  796. ;
  797. */
  798.         mov     ax, WORD PTR bc         /* get beginning column */
  799.         mov     bl, al                  /* keep it in bl */
  800.         mov     ax, WORD PTR ec         /* get ending column */
  801.         mov     bh, al                  /* keep it in bh */
  802.         mov     ax, WORD PTR normal     /* get normal attribute */
  803.         mov     dl, al                  /* keep it in dl */
  804.         mov     ax, WORD PTR block      /* get block attribute */
  805.         mov     dh, al                  /* keep it in dh */
  806.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  807.         mov     ch, al                  /* keep it in ch */
  808.         xor     cl, cl                  /* col = 0, keep col in cl */
  809. /*
  810. ;
  811. ; load screen and text pointer
  812. ;
  813. */
  814.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  815.         add     di, WORD PTR off                /* add offset of line */
  816.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  817.         mov     es, ax
  818.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  819.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  820.         mov     ds, ax                  /* move segment of text in ds */
  821.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  822.         jne     not_null                /* no, output string */
  823.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  824.         je      dspl_eol                /* yes, clear end of line */
  825.    }
  826. not_null:
  827.  
  828.    ASSEMBLE {
  829.         cmp     cl, ch                  /* is col == max_col? */
  830.         jge     getout                  /* yes, thru with line */
  831.         cmp     cl, BYTE PTR len        /* is col == len? */
  832.         je      dspl_eol                /* yes, must check block past eol */
  833.    }
  834. top:
  835.  
  836.    ASSEMBLE {
  837.         lodsb                   /* get next char in string */
  838.         mov     ah, dl          /* assume normal attribute */
  839.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  840.         jl      ch_out1         /* yes, show char and normal attribute */
  841.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  842.         jg      ch_out1         /* yes, show char and normal attribute */
  843.         mov     ah, dh          /* must be in a block - block attribute */
  844.    }
  845. ch_out1:
  846.  
  847.    ASSEMBLE {
  848.         stosw                   /* now show char on screen w/ attribute */
  849.         inc     cl              /* ++col */
  850.         cmp     cl, ch          /* is col == max_col? */
  851.         jge     getout          /* yes, thru with line */
  852.         cmp     cl, BYTE PTR len        /* is col == len? */
  853.         jl      top             /* yes, must check block past eol */
  854.    }
  855. dspl_eol:
  856.  
  857.    ASSEMBLE {
  858.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  859.         je      block_eol       /* show_eol flag is FALSE, blank line */
  860.         mov     al, EOL_CHAR    /* load some eol indicator */
  861.         mov     ah, dl          /* assume normal attribute */
  862.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  863.         jl      ch_out2         /* yes, show char and normal attribute */
  864.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  865.         jg      ch_out2         /* yes, show char and normal attribute */
  866.         mov     ah, dh          /* must be in a block - show block attribute */
  867.    }
  868. ch_out2:
  869.  
  870.    ASSEMBLE {
  871.         stosw                   /* write eol and attribute to screen */
  872.         inc     cl              /* ++col */
  873.         cmp     cl, ch          /* is col == max_col? */
  874.         je      getout          /* yes, we're done */
  875.    }
  876. block_eol:
  877.  
  878.    ASSEMBLE {
  879.         mov     al, ' '         /* clear rest of line w/ spaces */
  880.    }
  881. b1:
  882.  
  883.    ASSEMBLE {
  884.         mov     ah, dl          /* assume normal attribute */
  885.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  886.         jl      ch_out3         /* yes, show char and normal attribute */
  887.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  888.         jg      ch_out3         /* yes, show char and normal attribute */
  889.         mov     ah, dh          /* must be in a block - show block attribute */
  890.    }
  891. ch_out3:
  892.  
  893.    ASSEMBLE {
  894.         stosw                   /* write blank and attribute to screen */
  895.         inc     cl              /* ++col */
  896.         cmp     cl, ch          /* is col == max_col? */
  897.         jl      b1              /* while less output block */
  898.    }
  899. getout:
  900.  
  901.    ASSEMBLE {
  902.         pop     di
  903.         pop     si
  904.         pop     ds
  905.       }
  906.  
  907. /*
  908.       screen_ptr += off;
  909.       bcol = window->start_col;
  910.       for (col=0; col < max_col; col++, bcol++) {
  911.          attr = normal;
  912.          if (col >= bc && col <= ec)
  913.             attr = block;
  914.          if (col < len)
  915.             c = *text++;
  916.          else if (col == len && show_eol)
  917.             c = EOL_CHAR;
  918.          else
  919.             c = ' ';
  920.          *screen_ptr++ = c;
  921.          *screen_ptr++ = attr;
  922.  
  923.          c_output( c, bcol, line, attr );
  924.       }
  925. */
  926.    } else if (block_line == TRUE && file->block_type == STREAM &&
  927.               (rline == file->block_br || rline == file->block_er)) {
  928.       if (rline == file->block_br)
  929.          bc = file->block_bc;
  930.       else {
  931.          bc = file->block_ec + 1;
  932.          ec = normal;
  933.          normal = block;
  934.          block = ec;
  935.       }
  936.       if (bc < bcol)
  937.          bc = 0;
  938.       else if (bc < bcol + max_col)
  939.          bc = bc - bcol;
  940.       else
  941.          bc = max_col + 1;
  942.  
  943.  
  944.    ASSEMBLE {
  945.         /*
  946.         ; Register strategy:
  947.         ;   bl == beginning column
  948.         ;   bh == relative line length
  949.         ;   dl == normal text attribute
  950.         ;   dh == block attribute
  951.         ;   cl == current virtual column
  952.         ;   ch == maximum columns in window
  953.         ;   ES:DI == screen pointer (destination)
  954.         ;   DS:SI == text pointer (source)
  955.         ;   [bp+show_eol]  == access for local C variable
  956.         */
  957.  
  958.         push    ds                      /* MUST save ds - push it on stack */
  959.         push    si                      /* save si on stack */
  960.         push    di                      /* save di on stack */
  961.  
  962. /*
  963. ;
  964. ; set up local register variables
  965. ;
  966. */
  967.         mov     ax, WORD PTR bc         /* get beginning column */
  968.         mov     bl, al                  /* keep it in bl */
  969.         mov     ax, WORD PTR len        /* get relative line length */
  970.         mov     bh, al                  /* keep it in bh */
  971.         mov     ax, WORD PTR normal     /* get normal attribute */
  972.         mov     dl, al                  /* keep it in dl */
  973.         mov     ax, WORD PTR block      /* get block attribute */
  974.         mov     dh, al                  /* keep it in dh */
  975.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  976.         mov     ch, al                  /* keep it in ch */
  977.         xor     cl, cl                  /* col = 0, keep col in cl */
  978. /*
  979. ;
  980. ; load screen and text pointer
  981. ;
  982. */
  983.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  984.         add     di, WORD PTR off                /* add offset of line */
  985.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  986.         mov     es, ax
  987.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  988.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  989.         mov     ds, ax                  /* move segment of text in ds */
  990.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  991.         jne     nott_null               /* no, output string */
  992.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  993.         je      ddspl_eol               /* yes, clear end of line */
  994.    }
  995. nott_null:
  996.  
  997.    ASSEMBLE {
  998.         cmp     cl, ch          /* is col == max_col? */
  999.         je      ggetout         /* yes, thru with line */
  1000.         cmp     cl, bh          /* is col == len? */
  1001.         je      ddspl_eol       /* yes, check eol display */
  1002.    }
  1003. ttop:
  1004.  
  1005.    ASSEMBLE {
  1006.         lodsb                   /* get next char in string */
  1007.         mov     ah, dl          /* assume normal attribute */
  1008.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1009.         jl      str_out1        /* yes, show char and normal attribute */
  1010.         mov     ah, dh          /* must be in a block - show block attribute */
  1011.    }
  1012. str_out1:
  1013.  
  1014.    ASSEMBLE {
  1015.         stosw                   /* else show char on screen */
  1016.         inc     cl              /* ++col */
  1017.         cmp     cl, ch          /* is col == max_col? */
  1018.         je      ggetout         /* yes, thru with line */
  1019.         cmp     cl, bh          /* is col == len? */
  1020.         jl      ttop            /* yes, check eol display */
  1021.    }
  1022. ddspl_eol:
  1023.  
  1024.    ASSEMBLE {
  1025.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1026.         je      stream_eol      /* show_eol flag is FALSE, blank line */
  1027.         mov     al, EOL_CHAR    /* load some eol indicator */
  1028.         mov     ah, dl          /* assume normal attribute */
  1029.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1030.         jl      str_out2        /* yes, show char and normal attribute */
  1031.         mov     ah, dh          /* must be in a block - show block attribute */
  1032.    }
  1033. str_out2:
  1034.  
  1035.    ASSEMBLE {
  1036.         stosw                   /* write blank and attribute to screen */
  1037.         inc     cl              /* ++col */
  1038.         cmp     cl, ch          /* is col == max_col? */
  1039.         jge     ggetout         /* yes, we're done */
  1040.    }
  1041. stream_eol:
  1042.  
  1043.    ASSEMBLE {
  1044.         mov     al, ' '         /* clear rest of line w/ spaces */
  1045.    }
  1046. c1:
  1047.  
  1048.    ASSEMBLE {
  1049.         mov     ah, dl          /* assume normal attribute */
  1050.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1051.         jl      str_out3        /* yes, show char and normal attribute */
  1052.         mov     ah, dh          /* must be in a block - show block attribute */
  1053.    }
  1054. str_out3:
  1055.  
  1056.    ASSEMBLE {
  1057.         stosw                   /* write blank and attribute to screen */
  1058.         inc     cl              /* ++col */
  1059.         cmp     cl, ch          /* is col == max_col? */
  1060.         jl      c1              /* while less output block */
  1061.    }
  1062. ggetout:
  1063.  
  1064.    ASSEMBLE {
  1065.         pop     di
  1066.         pop     si
  1067.         pop     ds
  1068.       }
  1069.  
  1070. /*
  1071.       screen_ptr += off;
  1072.       bcol = window->start_col;
  1073.       for (col=0; col < max_col; col++, bcol++) {
  1074.          attr = normal;
  1075.          if (col >= bc && col <= ec)
  1076.             attr = block;
  1077.          if (col < len)
  1078.             c = *text++;
  1079.          else if (col == len && show_eol)
  1080.             c = EOL_CHAR;
  1081.          else
  1082.             c = ' ';
  1083.          *screen_ptr++ = c;
  1084.          *screen_ptr++ = attr;
  1085.          c_output( c, bcol, line, attr );
  1086.       }
  1087. */
  1088.    } else {
  1089.       if (block_line)
  1090.          attr = block;
  1091.       else
  1092.          attr = normal;
  1093.  
  1094.       assert( len >= 0 );
  1095.       assert( len <= MAX_COLS );
  1096.  
  1097.    ASSEMBLE {
  1098.         /*
  1099.         ; Register strategy:
  1100.         ;   bl == normal text attribute
  1101.         ;   bh == relative line length
  1102.         ;   cl == current virtual column
  1103.         ;   ch == maximum columns in window
  1104.         ;   ES:DI == screen pointer (destination)
  1105.         ;   DS:SI == text pointer (source)
  1106.         ;   [bp+show_eol]  == access for local C variable
  1107.         */
  1108.  
  1109.         mov     dx, ds          /* MUST save ds - keep it in dx */
  1110.         push    di              /* save di on stack */
  1111.         push    si              /* save si on stack */
  1112.  
  1113.  
  1114.         mov     bx, WORD PTR attr               /* keep attribute in bl */
  1115.         mov     ax, WORD PTR len                /* get normalized len */
  1116.         mov     bh, al                          /* keep len in bh */
  1117.         mov     cx, WORD PTR max_col            /* get max_col in cx */
  1118.         mov     ch, cl                          /* keep it in ch */
  1119.         xor     cl, cl                          /* zero out cl */
  1120.         mov     di, WORD PTR screen_ptr         /* load OFFST of screen ptr */
  1121.         add     di, WORD PTR off                /* add offset of line */
  1122.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1123.         mov     es, ax
  1124.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1125.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1126.         mov     ds, ax                  /* move segment of text in ds */
  1127.         cmp     si, 0                   /* is offset of pointer == NULL? */
  1128.         jne     nnot_null               /* no, output string */
  1129.         cmp     ax, 0                   /* is segment of pointer == NULL? */
  1130.         je      normeol                 /* yes, then clear rest of line */
  1131.    }
  1132. nnot_null:
  1133.  
  1134.    ASSEMBLE {
  1135.         mov     ah, bl                  /* get attribute */
  1136.         cmp     cl, ch          /* compare count with max columns */
  1137.         jge     getoutt         /* yes, thru with line */
  1138.         cmp     cl, bh          /* compare count with len */
  1139.         je      normeol         /* yes, clear end of line */
  1140.    }
  1141. topp:
  1142.  
  1143.    ASSEMBLE {
  1144.         lodsb                   /* get next char in string */
  1145.         stosw                   /* else show char on screen */
  1146.         inc     cl              /* ++col, count up to max_column */
  1147.         cmp     cl, ch          /* compare count with max columns */
  1148.         jge     getoutt         /* yes, thru with line */
  1149.         cmp     cl, bh          /* compare count with len */
  1150.         jl      topp            /* yes, clear end of line */
  1151.    }
  1152. normeol:
  1153.  
  1154.    ASSEMBLE {
  1155.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1156.         je      clreol          /* show_eol flag is FALSE, blank line */
  1157.         mov     al, EOL_CHAR    /* load some eol indicator */
  1158.         mov     ah, bl          /* assume normal attribute */
  1159.         stosw                   /* write blank and attribute to screen */
  1160.         inc     cl              /* ++col */
  1161.         cmp     cl, ch          /* is col == max_col? */
  1162.         jge     getoutt         /* yes, we're done */
  1163.    }
  1164. clreol:
  1165.  
  1166.    ASSEMBLE {
  1167.         mov     ah, bl          /* get attribute */
  1168.         mov     al, ' '         /* clear eol with ' ' */
  1169.         sub     ch, cl          /* find number of columns left */
  1170.         mov     cl, ch          /* put number of column left in cl */
  1171.         xor     ch, ch          /* clear ch */
  1172.         rep     stosw           /* count is in cx - set rest of line to ' ' */
  1173.    }
  1174. getoutt:
  1175.  
  1176.    ASSEMBLE {
  1177.         pop     si
  1178.         pop     di
  1179.         mov     ds, dx
  1180.       }
  1181.  
  1182. /*
  1183.       screen_ptr += off;
  1184.       bcol = window->start_col;
  1185.       for (col=0; col < max_col; col++, bcol++) {
  1186.          attr = normal;
  1187.          if (col < len)
  1188.             c = *text++;
  1189.          else if (col == len && show_eol)
  1190.             c = EOL_CHAR;
  1191.          else
  1192.             c = ' ';
  1193.          *screen_ptr++ = c;
  1194.          *screen_ptr++ = attr;
  1195.          c_output( c, bcol, line, attr );
  1196.       }
  1197. */
  1198.    }
  1199. }
  1200.  
  1201.  
  1202. /*
  1203.  * Name:    c_output
  1204.  * Purpose: Output one character on prompt lines
  1205.  * Date:    June 5, 1991
  1206.  * Passed:  c:     character to output to screen
  1207.  *          col:   col to display character
  1208.  *          line:  line number to display character
  1209.  *          attr:  attribute of character
  1210.  * Returns: none
  1211.  */
  1212. void c_output( int c, int col, int line, int attr )
  1213. {
  1214. void far *screen_ptr;
  1215. int  off;
  1216.  
  1217.    screen_ptr = (void far *)g_display.display_address;
  1218.    off = line * 160 + col * 2;
  1219.  
  1220.    ASSEMBLE {
  1221.         mov     bx, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1222.         add     bx, WORD PTR off                /* add offset of line:col */
  1223.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1224.         mov     es, ax
  1225.         mov     cx, WORD PTR attr       /* get attribute */
  1226.         mov     ah, cl                  /* put in ah */
  1227.         mov     cx, WORD PTR c          /* get character */
  1228.         mov     al, cl                  /* put in al */
  1229.         mov     WORD PTR es:[bx], ax    /* show char on screen */
  1230.    }
  1231.  
  1232. /*
  1233.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1234.    *screen_ptr++ = c;
  1235.    *screen_ptr = attr;
  1236. */
  1237. }
  1238.  
  1239.  
  1240. /*
  1241.  * Name:    s_output
  1242.  * Purpose: To output a string
  1243.  * Date:    June 5, 1991
  1244.  * Passed:  s:     string to output
  1245.  *          line:  line to display
  1246.  *          col:   column to begin display
  1247.  *          attr:  color to display string
  1248.  * Notes:   This function is used to output most strings not part of file text.
  1249.  */
  1250. void s_output( char far *s, int line, int col, int attr )
  1251. {
  1252. void far *screen_ptr;
  1253. int  off;
  1254. int  max_col;
  1255.  
  1256.    max_col = g_display.ncols;
  1257.    screen_ptr = (void far *)g_display.display_address;
  1258.    off = line * 160 + col * 2;
  1259.  
  1260.    ASSEMBLE {
  1261.         push    ds              /* save ds on stack */
  1262.         push    di              /* save di on stack */
  1263.         push    si              /* save si on stack */
  1264.  
  1265.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1266.         mov     cx, WORD PTR col                /* put cols in cx */
  1267.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1268.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1269.         add     di, WORD PTR off                /* add offset of line:col */
  1270.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1271.         mov     es, ax
  1272.         mov     si, WORD PTR s  /* load offset of string ptr */
  1273.         or      si, si          /* is it == NULL? */
  1274.         je      getout          /* yes, no output needed */
  1275.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  1276.         or      ax, ax          /* is pointer == NULL? */
  1277.         je      getout          /* yes, no output needed */
  1278.         mov     ds, ax          /* load segment of text in ds */
  1279.         mov     ah, bl          /* put attribute in AH */
  1280.    }
  1281. top:
  1282.  
  1283.    ASSEMBLE {
  1284.         cmp     cx, dx          /* col < max_cols? */
  1285.         jge     getout          /* no, thru with line */
  1286.         lodsb                   /* get next char in string - put in al */
  1287.         or      al, al          /* is it '\0' */
  1288.         je      getout          /* yes, end of string */
  1289.         cmp     al, 0x0a        /* is it '\n'? */
  1290.         je      getout          /* yes, end of string */
  1291.         stosw                   /* else show attr + char on screen (ah + al) */
  1292.         inc     cx              /* col++ */
  1293.         jmp     SHORT top       /* get another character */
  1294.    }
  1295. getout:
  1296.  
  1297.    ASSEMBLE {
  1298.         pop     si              /* get back si */
  1299.         pop     di              /* get back di */
  1300.         pop     ds              /* get back ds */
  1301.    }
  1302.  
  1303. /*
  1304.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1305.    max_col = g_display.ncols;
  1306.    while (*s && col < max) {
  1307.       *screen_ptr++ = *s++;
  1308.       *screen_ptr++ = attr;
  1309.    }
  1310. */
  1311. }
  1312.  
  1313.  
  1314. /*
  1315.  * Name:    eol_clear
  1316.  * Purpose: To clear the line from col to max columns
  1317.  * Date:    June 5, 1991
  1318.  * Passed:  col:   column to begin clear
  1319.  *          line:  line to clear
  1320.  *          attr:  color to clear
  1321.  * Notes:   Basic assembly
  1322.  */
  1323. void eol_clear( int col, int line, int attr )
  1324. {
  1325. int  max_col;
  1326. void far *screen_ptr;
  1327. int  off;
  1328.  
  1329.    max_col = g_display.ncols;
  1330.    screen_ptr = (void far *)g_display.display_address;
  1331.    off = line * 160 + col * 2;
  1332.  
  1333.    ASSEMBLE {
  1334.         push    di                              /* save di on stack */
  1335.  
  1336.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1337.         mov     dx, WORD PTR col                /* put cols in dx */
  1338.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1339.         cmp     dx, cx                          /* max_cols < cols? */
  1340.         jge     getout                          /* no, thru with line */
  1341.         sub     cx, dx                          /* number of column to clear */
  1342.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1343.         add     di, WORD PTR off                /* add offset of line:col */
  1344.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1345.         mov     es, ax
  1346.         mov     ah, bl                          /* get attribute in ah */
  1347.         mov     al, ' '                         /* store ' ' in al */
  1348.         rep     stosw                           /* clear to end of line */
  1349.    }
  1350. getout:
  1351.  
  1352.    ASSEMBLE {
  1353.         pop     di                              /* get back di from stack */
  1354.    }
  1355.  
  1356. /*
  1357.    for (; col < g_display.ncols; col++) {
  1358.       *p++ = ' ';
  1359.       *p++ = attr;
  1360.    }
  1361. */
  1362. }
  1363.  
  1364.  
  1365. /*
  1366.  * Name:    window_eol_clear
  1367.  * Purpose: To clear the line from start_col to end_col
  1368.  * Date:    June 5, 1991
  1369.  * Passed:  col:   column to begin clear
  1370.  *          line:  line to clear
  1371.  *          attr:  color to clear
  1372.  * Notes:   Basic assembly
  1373.  */
  1374. void window_eol_clear( WINDOW *window, int attr )
  1375. {
  1376. int  max_col;
  1377. void far *screen_ptr;
  1378. int  off;
  1379.  
  1380.    if (!g_status.screen_display)
  1381.       return;
  1382.    screen_ptr = (void far *)g_display.display_address;
  1383.    off = window->cline * 160 + window->start_col * 2;
  1384.    max_col = window->end_col + 1 - window->start_col;
  1385.  
  1386.    ASSEMBLE {
  1387.         push    di                              /* save di on stack */
  1388.  
  1389.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1390.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1391.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1392.         add     di, WORD PTR off                /* add offset of line:col */
  1393.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1394.         mov     es, ax
  1395.         mov     ah, bl                          /* get attribute in ah */
  1396.         mov     al, ' '                         /* store ' ' in al */
  1397.         rep     stosw                           /* clear to end of line */
  1398.  
  1399.         pop     di                              /* get back di from stack */
  1400.    }
  1401.  
  1402. /*
  1403.    for (; col < g_display.ncols; col++) {
  1404.       *p++ = ' ';
  1405.       *p++ = attr;
  1406.    }
  1407. */
  1408. }
  1409.  
  1410.  
  1411. /*
  1412.  * Name:    hlight_line
  1413.  * Date:    July 21, 1991
  1414.  * Passed:  x:     column to begin hi lite
  1415.  *          y:     line to begin hi lite
  1416.  *          lgth:  number of characters to hi lite
  1417.  *          attr:  attribute color
  1418.  * Notes:   The attribute byte is the hi byte.
  1419.  */
  1420. void hlight_line( int x, int y, int lgth, int attr )
  1421. {
  1422. int  off;
  1423. void far *screen_ptr;
  1424.  
  1425.    screen_ptr = (void far *)g_display.display_address;
  1426.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  1427.  
  1428.    ASSEMBLE {
  1429.         push    di              /* save di */
  1430.  
  1431.         mov     cx, lgth        /* number of characters to change color */
  1432.  
  1433.         mov     di, WORD PTR screen_ptr /* get destination - video memory */
  1434.         add     di, off                 /* add offset */
  1435.         mov     ax, WORD PTR screen_ptr+2
  1436.         mov     es, ax
  1437.         mov     ax, attr        /* attribute */
  1438.    }
  1439. lite_len:
  1440.  
  1441.    ASSEMBLE {
  1442.         stosb                   /* store a BYTE */
  1443.         inc     di              /* skip over character to next attribute */
  1444.         loop    lite_len        /* change next attribute */
  1445.         pop     di              /* restore di */
  1446.    }
  1447. }
  1448.  
  1449.  
  1450. /*
  1451.  * Name:    cls
  1452.  * Purpose: clear screen
  1453.  * Date:    June 5, 1991
  1454.  * Notes:   Call the video BIOS routine to clear the screen.
  1455.  */
  1456. void cls( void )
  1457. {
  1458. int  line;
  1459.  
  1460.      line = g_display.nlines + 1;
  1461.  
  1462.    ASSEMBLE {
  1463.         xor     ch, ch                  /* starting row in ch = 0 */
  1464.         xor     cl, cl                  /* starting column in cl = 0 */
  1465.         mov     ax, WORD PTR line       /* get ending row */
  1466.         mov     dh, al                  /* put it in dh */
  1467.         mov     dl, 79                  /* ending column in dl = 79 */
  1468.         mov     bh, 7                   /* attribute in bh  = 7 (normal) */
  1469.         mov     al, 0                   /* get number of lines */
  1470.         mov     ah, 6                   /* get function number */
  1471.         push    bp                      /* some BIOS versions wipe out bp */
  1472.         int     0x10
  1473.         pop     bp
  1474.    }
  1475. }
  1476.  
  1477.  
  1478. /*
  1479.  * Name:    set_cursor_size
  1480.  * Purpose: To set cursor size according to insert mode.
  1481.  * Date:    June 5, 1991
  1482.  * Passed:  csize:  desired cursor size
  1483.  * Notes:   use the global display structures to set the cursor size
  1484.  */
  1485. void set_cursor_size( int csize )
  1486. {
  1487.    ASSEMBLE {
  1488.         mov     ah, 1                   /* function 1 - set cursor size */
  1489.         mov     cx, WORD PTR csize      /* get cursor size ch:cl == top:bot */
  1490.         push    bp
  1491.         int     VIDEO_INT               /* video interrupt = 10h */
  1492.         pop     bp
  1493.    }
  1494. }
  1495.  
  1496.  
  1497. /*
  1498.  * Name:    set_overscan_color
  1499.  * Purpose: To set overscan color
  1500.  * Date:    April 1, 1993
  1501.  * Passed:  color:  overscan color
  1502.  * Notes:   before setting the overscan color, the old overscan color
  1503.  *           needs to be saved so it can be restored.
  1504.  */
  1505. void set_overscan_color( int color )
  1506. {
  1507.    ASSEMBLE {
  1508.         mov     ah, 0x0b                /* function 0x0b */
  1509.         mov     bl, BYTE PTR color      /* get new overscan color */
  1510.         xor     bh, bh
  1511.         push    bp
  1512.         int     VIDEO_INT               /* video interrupt = 10h */
  1513.         pop     bp
  1514.    }
  1515. }
  1516.  
  1517.  
  1518. /*
  1519.  * Name:    save_screen_line
  1520.  * Purpose: To save the characters and attributes of a line on screen.
  1521.  * Date:    June 5, 1991
  1522.  * Passed:  col:    desired column, usually always zero
  1523.  *          line:   line on screen to save (0 up to max)
  1524.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1525.  * Notes:   Save the contents of the line on screen where prompt is
  1526.  *           to be displayed
  1527.  */
  1528. void save_screen_line( int col, int line, char *screen_buffer )
  1529. {
  1530. char far *p;
  1531.  
  1532.    p = g_display.display_address + line * 160 + col * 2;
  1533.    _fmemcpy( screen_buffer, p, 160 );
  1534. }
  1535.  
  1536.  
  1537. /*
  1538.  * Name:    restore_screen_line
  1539.  * Purpose: To restore the characters and attributes of a line on screen.
  1540.  * Date:    June 5, 1991
  1541.  * Passed:  col:    usually always zero
  1542.  *          line:   line to restore (0 up to max)
  1543.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1544.  * Notes:   Restore the contents of the line on screen where the prompt
  1545.  *           was displayed
  1546.  */
  1547. void restore_screen_line( int col, int line, char *screen_buffer )
  1548. {
  1549. char far *p;
  1550.  
  1551.    p = g_display.display_address + line * 160 + col * 2;
  1552.    _fmemcpy( p, screen_buffer, 160 );
  1553. }
  1554.